/*******************************************************************
*
*    DESCRIPTION:Monitor and treat the queued packet
*
*    AUTHOR:LiuHui
*
*    HISTORY:
*
*    DATE:1/21/2007
*
*******************************************************************/
/** include files **/
#include <config.h>
#include <debug.h>
#include <header.h>
#include <xml_util.h>
#include <gui.h>
/** local definitions **/
#define BUFSIZE	2048
#define IPV4_INODE_OFFSET	91
#define IPV6_INODE_OFFSET	139
#define CMDLINE_BUF_LEN   4096
struct socket_cache_entry
{
  int protocol;
  struct in_addr local_addr;
  int local_port;
  struct in_addr remote_addr;
  int remote_port;
  int is_use;
};

struct process_cache_entry
{
  unsigned freq;
  pid_t pid;
  char path[_POSIX_PATH_MAX];

};

/* default settings */
#define PROC_FS_PATH	"/proc"
#define NETSTAT_TCP_PATH	"/proc/net/tcp"
#define NETSTAT_UDP_PATH	"/proc/net/udp"
#define NETSTAT_UDP6_PATH	"/proc/net/udp6"
#define NETSTAT_TCP6_PATH	"/proc/net/tcp6"

#define SOCKET_CACHE_ENTRY_MAX	64
#define PROCESS_CACHE_ENTRY_MAX 3
#define VISITED_MASK 0x80000000
#define UNVISITED_MASK 0x00000000

#define INPORT_ANY	0
/** external functions **/

/** external data **/

static char *script_process[] = {"/bin/bash",
                                 "/usr/bin/python",
                                 "/usr/bin/perl",
                                 NULL};
static char *shell_process[] = {"/bin/bash",
                                 "/bin/sh",
                                 "/bin/ash",
                                 "/bin/csh",
                                 "/bin/ksh",
                                 "/bin/zsh",
                                 "/bin/tcsh",
                                 NULL};
/** internal functions **/
static int get_inode(int proto, int local_port);
static int get_pid(int inode_num);
static void get_path_and_cmdline(pid_t pid, char *path, char *cmd_line);
static char *strnchr(const char *s, char x, int n);
static void add_socket_cache_entry(int protocol, struct in_addr local_addr,
                                   int local_port, struct in_addr remote_addr, int remote_port); 
static int is_cache_hint(int protocol, struct in_addr local_addr,
                         int local_port, struct in_addr remote_addr, int remote_port);
static int is_process_cache_hint(pid_t pid,const char* path);
static void add_process_cache_entry(pid_t pid,const char * path);
static int is_script_explain_process(const char *path);
static void get_script_file_path(const char *cmdline, char *path);
static struct list_head * get_process_backtrace(int pid);

/** public data **/

/** private data **/
static struct socket_cache_entry    socket_cache[SOCKET_CACHE_ENTRY_MAX];
static struct process_cache_entry   process_cache[PROCESS_CACHE_ENTRY_MAX];

static int front = 0;

/** public functions **/
void *packet_monitor(void *data)
{
  int result = 0;
  int local_port = 0, remote_port = 0; 
  int protocol = 0, hook = 0;
  pid_t pid = 0;
  int inode_number = 0;
  char cmdline[CMDLINE_BUF_LEN] = {0};
  char path[_POSIX_PATH_MAX] = {0};
  struct in_addr local_addr;
  struct in_addr remote_addr;
  struct ipq_handle *h = NULL;
  ipq_packet_msg_t *m = NULL;
  struct iphdr *ip = NULL;
  struct tcphdr *tcp = NULL;
  unsigned char buf[BUFSIZE] = {0};
  __MONITOR_DEBUG("Enter packet_monitor thread,pid:%d\n", getpid());
  pthread_detach(pthread_self());
  memset(socket_cache, 0, SOCKET_CACHE_ENTRY_MAX * sizeof(struct socket_cache_entry));
  memset(process_cache, 0 ,PROCESS_CACHE_ENTRY_MAX * sizeof(struct process_cache_entry));

  h = ipq_create_handle(0, PF_INET);
  if (NULL == h)
  {
    __ERROR_MSG("Error when ipq_create_handle.So exist thread\n");
    goto out;
  }
  result = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
  if (result < 0)
  {
    __ERROR_MSG("Error when ipq_set_mode\n");
    goto out;
  }
  /*Enter main loop*/
  while (1)
  {
    memset(buf, 0, BUFSIZE);
    memset(path, 0, _POSIX_PATH_MAX);
    memset(cmdline, 0, CMDLINE_BUF_LEN);

    result = ipq_read(h, buf, BUFSIZE, 0);
    if (result < 0)
    {
      __ERROR_MSG("Error when ipq_read\n");
      continue;
    }

    switch (ipq_message_type(buf))
    {
      case NLMSG_ERROR:
        {
          __ERROR_MSG("Received error message %d\n", ipq_get_msgerr(buf));
          break;
        }
      case IPQM_PACKET: 
        {
          m = ipq_get_packet(buf);
          hook = m->hook;
          ip = (struct iphdr *)m->payload;
          protocol = ip->protocol;
          /*Udp and tcp header's first 32 bit has the same meaning*/
          tcp = (struct tcphdr *)(m->payload + 4 * ip->ihl);
          if (NF_IP_LOCAL_OUT == hook)
          {
            local_addr.s_addr = ip->saddr;
            remote_addr.s_addr = ip->daddr;
            local_port = htons(tcp->source);
            remote_port = htons(tcp->dest);
          }
          else if (NF_IP_LOCAL_IN == hook)
          {
            local_addr.s_addr = ip->daddr;
            remote_addr.s_addr = ip->saddr;
            local_port = htons(tcp->dest);
            remote_port = htons(tcp->source);
          }

          /*
          __MONITOR_DEBUG("-------------------------------NEW PACKET %s-------------------------------\n",
                          NF_IP_LOCAL_OUT == hook ? "In output hook" : "In input hook");
          */
          if (is_cache_hint(protocol, local_addr, local_port,
                            remote_addr, remote_port))
          {
            /*Let packet go*/
            __MONITOR_DEBUG("Cache hint:local_port:%d, remote_port:%d\n",
                            local_port, remote_port);
            ipq_set_verdict(h, m->packet_id, NF_ACCEPT, 0, NULL);
          }
          else
          {
            inode_number = get_inode(protocol, local_port);
            if (-1 == inode_number)
            {
              ipq_set_verdict(h, m->packet_id, NF_DROP, 0, NULL);

              /*
              __MONITOR_DEBUG("can't find inode number. protocol:%s, local_port:%d, remote_port:%d\n",
                              protocol == IPPROTO_TCP ? "tcp" : "udp", local_port, remote_port);
              */

              break;
            }

            if (0 == inode_number)
            {
              __ERROR_MSG("Inode number can't be zero, protocol:%s, local_port:%d, remote_port:%d\n",
                          protocol == IPPROTO_TCP ? "tcp" : "udp", local_port, remote_port);
              ipq_set_verdict(h, m->packet_id, NF_DROP, 0, NULL);
              break;
            }
            __MONITOR_DEBUG("Find inode:%d, next to find pid\n", inode_number);
            pid = get_pid(inode_number);
            if (0 == pid)
            {
              __ERROR_MSG("Pid number can't be zero\n");
              ipq_set_verdict(h, m->packet_id, NF_DROP, 0, NULL);
              break;
            }
            __MONITOR_DEBUG("Find pid:%d, next to find path\n", pid);
            get_path_and_cmdline(pid, path, cmdline);
            __MONITOR_DEBUG("Find path:%s\n", path);

            if (!is_script_explain_process(path))
            {
              get_script_file_path(cmdline, path);
            }

            //see if it's in process cache
            if (is_process_cache_hint(pid, path))
            {
              __MONITOR_DEBUG("%d is in process cache,allowed.\n",pid);
              ipq_set_verdict(h,m->packet_id,NF_ACCEPT,0,NULL);
              break;
            }

            result = xml_is_allow_program((xmlChar *)path);
            if (1 == result)
            {
              /*Let packet go*/
              ipq_set_verdict(h, m->packet_id, NF_ACCEPT, 0, NULL);
              /*Add socket cache entry*/
              add_socket_cache_entry(protocol, local_addr,
                                     local_port, remote_addr, remote_port);
              //update process cache
              add_process_cache_entry(pid,path);

              __MONITOR_DEBUG("Program %s is allowed\n", path);
            }
            else if (0 == result)
            {
              /*Drop the packet*/
              __MONITOR_DEBUG("Program %s is not allowed\n", path);
              ipq_set_verdict(h, m->packet_id, NF_DROP, 0, NULL);
              /*Is also need a DROP cache?*/
            }
            else if (-1 == result)
            {
              /*Promopt to user*/
              popup_query_dialog(path, pid, m);
              /*Drop first packet*/
              ipq_set_verdict(h, m->packet_id, NF_DROP, 0, NULL);
            }
            //zyh add
            else if (-2 == result)
            {
              /*Show a warning message ,a temporary way... */
              __MONITOR_DEBUG("The program has been modified!!\n");
              popup_md5warn_dialog(path,pid,m->packet_id);

              ipq_set_verdict(h,m->packet_id,NF_DROP,0,NULL);

            }
          }
        }
        break;
      default:
        __ERROR_MSG("Unknown message type!\n");
        break;
    }
  }
  out:
  if (h != NULL)
  {
    ipq_destroy_handle(h);
  }

  return NULL;
}
/** private functions **/

/*
 *Function Name:get_inode
 *
 *Parameters:
 *proto -- protocol type
 *local_port -- local port
 *
 *Description:Get the inode number by the link info
 *	
 *Returns:The inode number.
 */
static int get_inode(int proto, int local_port)
{
  FILE *fp = NULL;
  FILE *fp1 = NULL;
  char buf[1024] = {0};
  char hex_local_port[10] = {0};
  int inode_num = -1;
  char *mark = NULL;
  char *mark1 = NULL;
  int i = 0;
  if (IPPROTO_TCP == proto)
  {
    fp = fopen(NETSTAT_TCP_PATH, "r");
  }
  else if (IPPROTO_UDP == proto)
  {
    fp = fopen(NETSTAT_UDP_PATH, "r");
  }
  if (NULL == fp)
  {
    __ERROR_MSG("Error when open %s\n",
                proto == IPPROTO_TCP ?  NETSTAT_TCP_PATH : NETSTAT_UDP_PATH );
    goto out;
  }
  /*Find in ipv4 stat file*/
  while (fgets(buf, 1024, fp) != NULL)
  {
    if (0 == i)
    {
      i ++;
      continue;
    }
    /*get souce port*/
    mark = strnchr(buf, ':', 2);
    if (NULL == mark)
    {
      __ERROR_MSG("Can't find local_port in %s\n",
                  proto == IPPROTO_TCP ? NETSTAT_TCP_PATH : NETSTAT_UDP_PATH);
      inode_num = -1;
      goto out;
    }
    /*get the pointer to hex_local_port*/
    mark ++;
    strncpy(hex_local_port, mark, 4);

    if (strtol(hex_local_port, NULL, 16) == local_port)
    {
      /*find inode number*/
      mark = buf + IPV4_INODE_OFFSET;/*point to inode number*/
      mark1 = strchr(mark, ' ');
      *mark1 = '\0';
      inode_num = atoi(mark);
      __MONITOR_DEBUG("Compare success, inode-number:%d\n", inode_num);
      goto out;
    }
    memset(buf, 0, 1024);
  }
  /*Find in ipv6 stat file*/
  if (IPPROTO_TCP == proto)
  {
    fp1 = fopen(NETSTAT_TCP6_PATH, "r");
  }
  else if (IPPROTO_UDP == proto)
  {
    fp1 = fopen(NETSTAT_UDP6_PATH, "r");
  }
  i = 0;
  mark = NULL;
  mark1 = NULL;
  memset(buf, 0, 1024);
  memset(hex_local_port, 0, 10);
  while (fgets(buf, 1024, fp1) != NULL)
  {
    if (0 == i)
    {
      i ++;
      continue;
    }
    /*get souce port*/
    mark = strnchr(buf, ':', 2);
    if (NULL == mark)
    {
      __ERROR_MSG("Can't find local_port in %s\n",
                  proto == IPPROTO_TCP ? NETSTAT_TCP6_PATH : NETSTAT_UDP6_PATH);
      inode_num = -1;
      goto out;
    }
    /*get the pointer to hex_local_port*/
    mark ++;
    strncpy(hex_local_port, mark, 4);

    if (strtol(hex_local_port, NULL, 16) == local_port)
    {
      /*find inode number*/
      mark = buf + IPV6_INODE_OFFSET;/*point to inode number*/
      mark1 = strchr(mark, ' ');
      *mark1 = '\0';
      inode_num = atoi(mark);
      __MONITOR_DEBUG("Compare success, inode-number:%d\n", inode_num);
      goto out;
    }

    memset(buf, 0, 1024);
  }
  out:
  if (fp != NULL)
  {
    fclose(fp);
    fp = NULL;
  }
  if (fp1 != NULL)
  {
    fclose(fp1);
    fp1 = NULL;
  }

  return inode_num;
}

/*
 *Function Name:get_pid
 *
 *Parameters:inode_num -- inode number
 *
 *Description:Because inode number is a unique number in system.So we can find pid by it.
 *
 *Returns:the process pid
 *
 */
static pid_t get_pid(int inode_num)
{
  DIR *dirp = NULL;
  DIR *fd_dirp = NULL;
  pid_t ret = 0;
  int result = 0;
  char cinode[10] = {0};
  struct dirent *direntp = NULL;
  struct dirent *res = NULL;
  struct dirent *direntp1 = NULL;
  struct dirent *res1 = NULL;
  char proc_fd_dir[64] = {0};

  char proc_fd_path[64] = {0};
  char fd_info[64] = {0};
  sprintf(cinode, "%d", inode_num);

  direntp = malloc(sizeof(struct dirent));
  memset(direntp, 0, sizeof(struct dirent));

  direntp1 = malloc(sizeof(struct dirent));
  memset(direntp1, 0, sizeof(struct dirent));
  if (NULL == direntp || NULL == direntp1)
  {
    __ERROR_MSG("Memory alloc error\n");
    goto out;
  }
  dirp = opendir(PROC_FS_PATH);
  while ((readdir_r(dirp, direntp, &res) == 0) && (res != NULL))
  {
    if ((direntp->d_type == 4) && (atoi(direntp->d_name) > 0))/*a process dir*/
    {
      sprintf(proc_fd_dir, "/proc/%s/fd", direntp->d_name);
      fd_dirp = opendir(proc_fd_dir);
      if (NULL == fd_dirp)
      {
        goto _next;
      }
      while ((readdir_r(fd_dirp, direntp1, &res1) == 0) && (res1 != NULL))
      {
        if (direntp1->d_type == 10)/*symbol link*/
        {
          sprintf(proc_fd_path, "%s/%s", proc_fd_dir, direntp1->d_name);
          result = readlink(proc_fd_path, fd_info, 64 -1);
          if (-1 == result)
          {
            __ERROR_MSG("Error when readlink\n");
            ret = 0;
            goto out;
          }
          if (strstr(fd_info, cinode) != NULL)
          {
            ret = atoi(direntp->d_name);
            __MONITOR_DEBUG("Pid found:%d\n", ret);
            goto out;
          }
        }
        memset(direntp1, 0, sizeof(struct dirent));
        memset(proc_fd_path, 0, 64);
        memset(fd_info, 0, 64);
        res1 = NULL;
      }
      if (fd_dirp != NULL)
      {
        closedir(fd_dirp);
        fd_dirp = NULL;
      }
    }
    _next:
    memset(proc_fd_dir, 0, 64);
    memset(direntp, 0, sizeof(struct dirent));
    res  = NULL;
  }
  out:
  if (dirp != NULL)
  {
    closedir(dirp);
    dirp = NULL;
  }
  if (fd_dirp != NULL)
  {
    closedir(fd_dirp);
    fd_dirp = NULL;
  }
  if (direntp != NULL)
  {
    free(direntp);
    direntp = NULL;
  }
  if (direntp1 != NULL)
  {
    free(direntp1);
    direntp1 = NULL;
  }
  return ret;
}
/*
 *Function Name:get_path_and_cmdline
 *
 *Parameters:pid -- the process id
 *
 *Description:Read the file under /proc/pid to get path and cmdline
 *
 *Returns:0 means error
 *
 */
static void get_path_and_cmdline(pid_t pid, char *path, char *cmd_line)
{
  int result = 0;
  FILE *fp = NULL;
  char path_exe[_POSIX_PATH_MAX] = {0};
  char path_cmdline[_POSIX_PATH_MAX] = {0};

  if (NULL == path || NULL == cmd_line)
  {
    return;
  }
  sprintf(path_exe, "/proc/%d/exe", pid);
  sprintf(path_cmdline, "/proc/%d/cmdline", pid);
  result = readlink(path_exe, path, _POSIX_PATH_MAX -1);
  if (-1 == result)
  {
    __ERROR_MSG("Error when readlink\n");
    goto out;
  }
  fp = fopen(path_cmdline, "r");
  fgets(cmd_line, CMDLINE_BUF_LEN-1, fp);
  out:
  if (fp != NULL)
  {
    fclose(fp);
  }
}
static char *strnchr(const char *s, char x, int n)
{
  int i = 0;
  char *temp = (char *)s;
  while (*temp)
  {
    if (*temp == x)
    {
      if (++i == n)
      {
        return temp;
      }
    }
    temp ++;
  }
  return NULL;
}
/*
 *Function Name:add_socket_cache_entry
 *
 *Parameters:
 *
 *Description:Add cache in the entry
 *
 *Returns:NULL
 *
 */
static void add_socket_cache_entry(int protocol, struct in_addr local_addr,
                                   int local_port, struct in_addr remote_addr, int remote_port)
{
  socket_cache[front].is_use = 1;
  socket_cache[front].local_addr = local_addr;
  socket_cache[front].local_port = local_port;
  socket_cache[front].remote_addr = remote_addr;
  socket_cache[front].remote_port = remote_port;
  front = (front + 1) % (SOCKET_CACHE_ENTRY_MAX - 1);
}
/*
 *Function Name:is_cache_hint
 *
 *Parameters:
 *
 *Description:
 *
 *Returns:
 *
 */
static int is_cache_hint(int protocol, struct in_addr local_addr,
                         int local_port, struct in_addr remote_addr, int remote_port)
{
  int i = 0;
  int ret = 0;
  for (i = 0; i < SOCKET_CACHE_ENTRY_MAX; i ++)
  {
    if (socket_cache[front].is_use)
    {
      if (protocol == socket_cache[front].protocol
          && local_addr.s_addr == socket_cache[front].local_addr.s_addr
          && local_port ==  socket_cache[front].local_port
          && remote_addr.s_addr == socket_cache[front].remote_addr.s_addr
          && remote_port == socket_cache[front].remote_port
         )
      {
        ret = 1;
        goto out;
      }
    }
  }
  out:
  return ret;
}

static int is_process_cache_hint(pid_t pid,const char * path)
{
  int ret=0,i;
  for (i=0;i<PROCESS_CACHE_ENTRY_MAX;i++)
  {
    process_cache[i].freq>>=1;
    if (pid==process_cache[i].pid &&
        !strcmp(path,process_cache[i].path))
    {
      ret=1;
      process_cache[i].freq|=VISITED_MASK;
    }

  }
  return ret;
}

static void add_process_cache_entry(pid_t pid,const char * path)
{
  unsigned i=0,add_location=0,min_freq=0xFFFFFFFF;
  for (i=0;i<PROCESS_CACHE_ENTRY_MAX;i++)
  {
    if (0 == process_cache[i].pid)
    {
      __MONITOR_DEBUG("Find a empty process_cache slot,added.\n");
      add_location=i;
      goto out;
    }
  }

  //reaching here means cache is full
  for (i=0;i<PROCESS_CACHE_ENTRY_MAX;i++)
  {
    if (process_cache[i].freq<min_freq)
    {
      min_freq=process_cache[i].freq;
      add_location=i;
    }
  }

  __MONITOR_DEBUG("A LRU replacement happend.\n");
  __MONITOR_DEBUG("Knockout index:%d,freq : %x\n",add_location,min_freq);
  __MONITOR_DEBUG("Knockout path : %s\n",process_cache[add_location].path);
  out:
  process_cache[add_location].freq=VISITED_MASK;
  process_cache[add_location].pid=pid;
  strcpy(process_cache[add_location].path,path);
  return;     
}

void del_process_cache_entry(const char * path)
{
  int i = 0;

  for (i = 0; i < PROCESS_CACHE_ENTRY_MAX; i++)
  {
    if (strcmp(path, process_cache[i].path) == 0)
    {
      __MONITOR_DEBUG("del a process_cache:%s\n", path);
      memset(&process_cache[i], 0, sizeof(struct process_cache_entry));
      break;
    }
  }
}

static int is_script_explain_process(const char *path)
{
  int i = 0;
  while(script_process[i])
  {
    if (strstr(path, script_process[i]))
      return 0;
    i++;
  }
  return -1;
}

static void get_script_file_path(const char *cmdline, char *path)
{
  int i = 0;
  struct stat s;

  for (i = 0; i < CMDLINE_BUF_LEN - 1; i++)
  {
    if ('\0' == cmdline[i])
    {
      i++;
      memset(path, 0, _POSIX_PATH_MAX);
      strcpy(path, (cmdline + i));
      if (!stat(path, &s))
      {
        __MONITOR_DEBUG("probe script file access network:%s\n", path);
        return ;
      }
      i += strlen(path);
    }
  }
  return ;
}

/*get the process parent process id by process id
 * return >0 :success
 * return 0 :fail
 */
static int get_process_ppid(int pid)
{
  int result = 0;
  FILE *fp = NULL;
  char path_stat[256] = {0};
  char buf[16] = {0};
  char ppid_buf[16] = {0};
  pid_t ppid = 0;

  sprintf(path_stat, "/proc/%d/stat", pid);
  fp = fopen(path_stat, "r");
  fgets(path_stat, 255, fp);
  if (fp != NULL)
  {
    fclose(fp);
  }
  ///pid comm state ppid pgrp session
  sscanf(path_stat, "%s %s %s %s %s %s", buf, buf, buf, ppid_buf, buf, buf);
  ppid = atoi(ppid_buf);
  return ppid;
}
/*
 * return 0:bottom
 * return -1: not bottom
 */
static int is_bottom_backtrace(int pid)
{
  int i = 0;
  int flag = 0;
  int offset = 0;
  char *pos = 0;
  char cmdline[CMDLINE_BUF_LEN] = {0};
  char path[_POSIX_PATH_MAX] = {0};

  get_path_and_cmdline(pid, path, cmdline);
  while(script_process[i])
  {
    if (strstr(cmdline, shell_process[i]))
    {
      flag = 1;
      break;
    }
    i++;
  }

  if (!flag)
  {
    return -1;
  }

  pos = strchr(cmdline, '\0');
  offset = (int)pos - (int)cmdline;

  for (i = offset + 1; i < CMDLINE_BUF_LEN - 1; i++)
  {
    if ('\0' != cmdline[i])
    {
      return -1;
    }
    if ((i - offset) > 10)
    {
      return 0;
    }
  }
  return 0;
}

struct backtrace_item
{
  struct list_head list;
  char cmdline[CMDLINE_BUF_LEN];
};

static struct list_head * get_process_backtrace(int pid)
{
  int result = -1;
  int i = 0;
  char cmdline[CMDLINE_BUF_LEN] = {0};
  char path[_POSIX_PATH_MAX] = {0};
  struct backtrace_item * backtrace = NULL;
  struct list_head *p = NULL;
  struct backtrace_item * item = NULL;

  struct list_head *head = malloc(sizeof(struct list_head));

  if (NULL == head)
  {
    __ERROR_MSG("Error when alloc memory\n");
    return NULL;
  }
  memset(head, 0, sizeof(struct list_head));
  INIT_LIST_HEAD(head);

  while(1)
  {
    result = is_bottom_backtrace(pid);

    get_path_and_cmdline(pid, path, cmdline);
    if (result)
    {
      ///not the bottom of backtrace
      for (i = 0; i < CMDLINE_BUF_LEN - 1; i++)
      {
        if (cmdline[i] == '\0' && cmdline[i+1] != '\0')
        {
          cmdline[i] = ' ';
        }
        else if ('\0' == cmdline[i] && '\0' == cmdline[i+1])
        {
          break;
        }
      }
    }
    ///add to list
    backtrace = malloc(sizeof(struct backtrace_item));
    if (NULL == backtrace)
    {
      __ERROR_MSG("Error when alloc memory\n");
      break;
    }
    memset(backtrace, 0, sizeof(struct backtrace_item));
    strcpy(backtrace->cmdline, cmdline);
    list_add(&backtrace->list, head);

    if (!result)
    {
      break;
    }
    pid = get_process_ppid(pid);
  }

  ///for debug
  list_for_each(p, head){
    item = list_entry(p, struct backtrace_item, list);
    __DEBUG_MSG("backtrace:%s\n", item->cmdline);
  }
  ///for debug

  return head;
}
